Skip to content

Refactor arcade heading hold, reverse steering - #115

Open
SaintSampo wants to merge 6 commits into
mainfrom
driveArcadeRefactor
Open

Refactor arcade heading hold, reverse steering#115
SaintSampo wants to merge 6 commits into
mainfrom
driveArcadeRefactor

Conversation

@SaintSampo

Copy link
Copy Markdown
Member

Summary

Cleans up arcade() and its IMU heading-hold, and fixes two teleop feel issues. Single file, differential_drive.py.

Changes

  • Collapsed the heading-hold state machine. The two flags turning + reset_heading are replaced by one _holding_heading. Same behavior across every transition, far less to reason about. arcade() is flattened to early returns instead of 3-deep nesting, and the misnamed left_speed/right_speed (they're efforts) become left/right.

  • Joystick deadband (0.1). Inputs below the threshold on either axis snap to zero, so idle-stick drift no longer creeps or slowly turns the robot. Also means near-center turn resolves to exactly 0, so heading-hold engages instead of being disabled by drift.

  • Reverse steering fix. Pushing back-and-left used to curve the robot right (the turn kept the same rotation direction as forward). Turn is now flipped when reversing, so the robot steers toward the stick either way.

  • Stop forgets the held heading. A neutral (0, 0) clears _holding_heading, so resuming straight recaptures the current heading rather than steering back toward the pre-stop one.

  • Fresh PID per straight segment. heading_pid.clear_history() on entering straight prevents a prior turn's elapsed time from leaking into the controller's first derivative/integral step.

  • Per-board heading gains. The single kp=0.075, kd=0.001 is replaced with tuned values: non-Nano kp=0.064, kd=0.0045, Nano kp=0.014, kd=0.001.

Notes

  • Behavior changes worth knowing for existing code: the deadband, the reverse turn-flip, and the new heading gains all change how teleop drives.
  • self.turning and self.reset_heading are gone (nothing else in XRPLib referenced them); the internal flag is now self._holding_heading.

Testing

Driven via gamepad teleop on hardware — deadband, reverse steering, and straight-line heading hold all confirmed by feel. Autonomous straight()/turn() are unaffected (they don't use heading_pid).

Replace reset_heading/turning flags with a single _holding_heading flag and simplify arcade mixing logic. Use early returns, keep wheel-mixing/scaling behavior, and centralize IMU-assisted straight driving: capture heading on entry, hold it while straight, and clear the hold when turning. Improves readability and fixes heading recapture behavior when transitioning between turning and straight driving.
When driving backward the turn input is inverted so the robot steers toward the joystick the same way as when driving forward. Adds a check in DifferentialDrive to negate `turn` if `straight` is negative before mixing, preserving the existing mixing and scaling logic and preventing reversed steering behavior.
@fgrossman

fgrossman commented Aug 7, 2026 via email

Copy link
Copy Markdown
Collaborator

@SaintSampo

Copy link
Copy Markdown
Member Author

My thinking was that without a deadband, there is not much point of having a control loop maintain heading. A stick will almost never be at exactly zero. Very few users are going to know to add a deadband. But I can remove it, if it is technically more correct.

Future idea: I think a drivetrain class like this should make it easy for users to set and tune a min_input, max_input, deadband, and input exponential. Low priority but I want to revisit this at some point.

@SaintSampo SaintSampo changed the title Refactor arcade heading hold. Add deadband and reverse steering Refactor arcade heading hold, reverse steering Aug 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants